/**
 * @file instruction.cpp
 * @brief VimL虚拟机指令集实现
 * @author VimLVM Team
 * @date 2025
 */

#include "viml/instruction.h"
#include <sstream>

namespace viml {

Instruction Instruction::load_const(uint8_t reg, uint32_t const_index) {
    return Instruction(OpCode::LOAD_CONST, reg, 0, 0, const_index);
}

Instruction Instruction::binary_op(OpCode op, uint8_t dest, uint8_t left, uint8_t right) {
    return Instruction(op, dest, left, right, 0);
}

Instruction Instruction::jump(OpCode op, uint32_t offset) {
    return Instruction(op, 0, 0, 0, offset);
}

Instruction Instruction::call(uint8_t func_reg, uint8_t argc) {
    return Instruction(OpCode::CALL, func_reg, argc, 0, 0);
}

Instruction Instruction::list_append(uint8_t list_reg, uint8_t value_reg) {
    return Instruction(OpCode::LIST_APPEND, list_reg, value_reg, 0, 0);
}

Instruction Instruction::dict_set(uint8_t dict_reg, uint8_t key_reg, uint8_t value_reg) {
    return Instruction(OpCode::DICT_SET, dict_reg, key_reg, value_reg, 0);
}

std::string Instruction::to_string() const {
    std::ostringstream oss;
    
    switch (opcode) {
        case OpCode::LOAD_CONST: 
            oss << "LOAD_CONST R" << static_cast<int>(a) << " K" << bx; 
            break;
        case OpCode::LOAD_NIL: 
            oss << "LOAD_NIL R" << static_cast<int>(a); 
            break;
        case OpCode::LOAD_TRUE: 
            oss << "LOAD_TRUE R" << static_cast<int>(a); 
            break;
        case OpCode::LOAD_FALSE: 
            oss << "LOAD_FALSE R" << static_cast<int>(a); 
            break;
        case OpCode::MOVE: 
            oss << "MOVE R" << static_cast<int>(a) << " R" << static_cast<int>(b); 
            break;
        case OpCode::ADD: 
            oss << "ADD R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::SUB: 
            oss << "SUB R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::MUL: 
            oss << "MUL R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::DIV: 
            oss << "DIV R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::MOD: 
            oss << "MOD R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::NEG: 
            oss << "NEG R" << static_cast<int>(a) << " R" << static_cast<int>(b); 
            break;
        case OpCode::AND: 
            oss << "AND R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::OR: 
            oss << "OR R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::NOT: 
            oss << "NOT R" << static_cast<int>(a) << " R" << static_cast<int>(b); 
            break;
        case OpCode::EQ: 
            oss << "EQ R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::NE: 
            oss << "NE R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::LT: 
            oss << "LT R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::LE: 
            oss << "LE R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::GT: 
            oss << "GT R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::GE: 
            oss << "GE R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::JMP: 
            oss << "JMP " << bx; 
            break;
        case OpCode::JMP_IF_TRUE: 
            oss << "JMP_IF_TRUE R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::JMP_IF_FALSE: 
            oss << "JMP_IF_FALSE R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::CALL: 
            oss << "CALL R" << static_cast<int>(a) << " " << static_cast<int>(b); 
            break;
        case OpCode::RETURN_OP: return "RETURN";
            oss << "RETURN R" << static_cast<int>(a); 
            break;
        case OpCode::LOAD_GLOBAL: 
            oss << "LOAD_GLOBAL R" << static_cast<int>(a) << " K" << bx; 
            break;
        case OpCode::STORE_GLOBAL: 
            oss << "STORE_GLOBAL K" << bx << " R" << static_cast<int>(a); 
            break;
        case OpCode::LOAD_LOCAL: 
            oss << "LOAD_LOCAL R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::STORE_LOCAL: 
            oss << "STORE_LOCAL " << bx << " R" << static_cast<int>(a); 
            break;
        case OpCode::LOAD_UPVALUE: 
            oss << "LOAD_UPVALUE R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::STORE_UPVALUE: 
            oss << "STORE_UPVALUE " << bx << " R" << static_cast<int>(a); 
            break;
        case OpCode::NEW_LIST: 
            oss << "NEW_LIST R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::NEW_DICT: 
            oss << "NEW_DICT R" << static_cast<int>(a) << " " << bx; 
            break;
        case OpCode::GET_INDEX: 
            oss << "GET_INDEX R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::SET_INDEX: 
            oss << "SET_INDEX R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::LIST_APPEND: 
            oss << "LIST_APPEND R" << static_cast<int>(a) << " R" << static_cast<int>(b); 
            break;
        case OpCode::DICT_SET: 
            oss << "DICT_SET R" << static_cast<int>(a) << " R" << static_cast<int>(b) << " R" << static_cast<int>(c); 
            break;
        case OpCode::BREAKPOINT: 
            oss << "BREAKPOINT"; 
            break;
        case OpCode::HALT: 
            oss << "HALT"; 
            break;
    }
    
    return oss.str();
}

std::string to_string(OpCode opcode) {
    switch (opcode) {
        case OpCode::LOAD_CONST: return "LOAD_CONST";
        case OpCode::LOAD_NIL: return "LOAD_NIL";
        case OpCode::LOAD_TRUE: return "LOAD_TRUE";
        case OpCode::LOAD_FALSE: return "LOAD_FALSE";
        case OpCode::MOVE: return "MOVE";
        case OpCode::ADD: return "ADD";
        case OpCode::SUB: return "SUB";
        case OpCode::MUL: return "MUL";
        case OpCode::DIV: return "DIV";
        case OpCode::MOD: return "MOD";
        case OpCode::NEG: return "NEG";
        case OpCode::AND: return "AND";
        case OpCode::OR: return "OR";
        case OpCode::NOT: return "NOT";
        case OpCode::EQ: return "EQ";
        case OpCode::NE: return "NE";
        case OpCode::LT: return "LT";
        case OpCode::LE: return "LE";
        case OpCode::GT: return "GT";
        case OpCode::GE: return "GE";
        case OpCode::JMP: return "JMP";
        case OpCode::JMP_IF_TRUE: return "JMP_IF_TRUE";
        case OpCode::JMP_IF_FALSE: return "JMP_IF_FALSE";
        case OpCode::CALL: return "CALL";
        case OpCode::RETURN_OP: return "RETURN";
        case OpCode::LOAD_GLOBAL: return "LOAD_GLOBAL";
        case OpCode::STORE_GLOBAL: return "STORE_GLOBAL";
        case OpCode::LOAD_LOCAL: return "LOAD_LOCAL";
        case OpCode::STORE_LOCAL: return "STORE_LOCAL";
        case OpCode::LOAD_UPVALUE: return "LOAD_UPVALUE";
        case OpCode::STORE_UPVALUE: return "STORE_UPVALUE";
        case OpCode::NEW_LIST: return "NEW_LIST";
        case OpCode::NEW_DICT: return "NEW_DICT";
        case OpCode::GET_INDEX: return "GET_INDEX";
        case OpCode::SET_INDEX: return "SET_INDEX";
        case OpCode::LEN: return "LEN";
        case OpCode::LIST_APPEND: return "LIST_APPEND";
        case OpCode::DICT_SET: return "DICT_SET";
        case OpCode::BREAKPOINT: return "BREAKPOINT";
        case OpCode::ECHO: return "ECHO";
        case OpCode::HALT: return "HALT";
        default: return "UNKNOWN";
    }
}
} // namespace viml